import tkinter as tk
import json
import os
import threading
import imaplib
import email
import base64
import hashlib
import uuid
from email.header import decode_header
from tkinter import ttk, filedialog, messagebox
from cryptography.fernet import Fernet

class ReceiveFromEmail():
    def __init__(self):
        self.root = tk.Tk()
        self.root.withdraw()    # 隐藏窗口
        self.root.title("ReceiveFromEmail")
        self.root.geometry("300x500")
        self.root.resizable(False, False)

        try:
            # 直接读取根目录下的icon.ico文件
            root_dir = os.path.dirname(os.path.abspath(__file__))
            icon_path = os.path.join(root_dir, 'logo.ico')
            
            # 如果图标文件存在，则设置对话框图标
            if os.path.exists(icon_path):
                self.root.iconbitmap(icon_path)
        except Exception as e:
            # 如果设置图标失败，不中断程序运行
            print(f"设置对话框图标失败: {e}")
            pass
        
        # 初始化邮箱账户列表
        self.accounts = {}
        self.current_account = None

        # 创建界面组件
        self.create_widgets()  # 修正拼写错误

        # 加载已保存的设置
        self.load_settings()

        self.center_window()    # 居中窗口
        self.root.deiconify()   # 显示窗口

    def create_widgets(self):  # 修正拼写错误
        main_frame = tk.Frame(self.root)
        main_frame.pack(padx=5, fill="both", expand=True)

        # 待收邮箱框架
        receive_mail_frame = tk.LabelFrame(main_frame, padx=10, pady=5)
        receive_mail_frame.pack(fill="x", padx=10, pady=5)

        # 待收邮箱
        email_frame = tk.Frame(receive_mail_frame)
        email_frame.pack(fill="x", pady=5)
        tk.Label(email_frame, text="待收邮箱:", width=11, anchor="w").pack(side="left")
        self.email_combobox = ttk.Combobox(email_frame)
        self.email_combobox.pack(side="left", expand=True, fill="x")
        self.email_combobox.bind("<<ComboboxSelected>>", self.on_account_selected)
        
        # IMAP服务器
        server_frame = tk.Frame(receive_mail_frame)
        server_frame.pack(fill="x", pady=(0,5))
        tk.Label(server_frame, text="IMAP服务器:", width=11, anchor="w").pack(side="left")
        self.imap_server_entry = tk.Entry(server_frame)
        self.imap_server_entry.pack(side="left", expand=True, fill="x")
        self.imap_server_entry.insert(0, "imap.example.com")
        
        # IMAP端口
        port_frame = tk.Frame(receive_mail_frame)
        port_frame.pack(fill="x", pady=(0,5))
        tk.Label(port_frame, text="端口:", width=11, anchor="w").pack(side="left")
        self.imap_port_entry = tk.Entry(port_frame)
        self.imap_port_entry.pack(side="left",expand=True, fill="x")
        self.imap_port_entry.insert(0, "993")  # 修改为正确的IMAP SSL端口

        # 密码
        password_frame = tk.Frame(receive_mail_frame)
        password_frame.pack(fill="x", pady=(0,5))
        tk.Label(password_frame, text="密码/授权码:", width=11, anchor="w").pack(side="left")
        self.password_entry = tk.Entry(password_frame, width=18, show="*")
        self.password_entry.pack(side="left")
        self.imap_password_visible = False  # 跟踪IMAP密码是否可见
        self.toggle_imap_password_button = tk.Button(password_frame, text="👁", command=self.toggle_imap_password_visibility)
        self.toggle_imap_password_button.pack(side="right")

        # 按钮框架
        button_frame = tk.Frame(receive_mail_frame)
        button_frame.pack(fill="x", pady=(0,5))
        tk.Button(button_frame, text="保存账户设置", command=self.save_settings).pack(side="left", padx=(0,5), expand=True, fill="x")
        tk.Button(button_frame, text="删除账户", command=self.delete_account).pack(side="right", padx=(5,0),expand=True, fill="x")

        # 附件框架
        file_frame = tk.LabelFrame(main_frame, padx=10, pady=5)
        file_frame.pack(fill="x", padx=10, pady=(0,10))
        
        # 保存路径
        path_frame = tk.Frame(file_frame)
        path_frame.pack(fill="x", pady=(0,5))
        tk.Label(path_frame, text="保存到:", width=6, anchor="w").pack(side="left")
        self.file_path_entry = tk.Entry(path_frame, width=15)
        self.file_path_entry.pack(side="left", expand=True, fill="x")
        self.file_path_button = tk.Button(path_frame, text="浏览",command=self.browse_folder)
        self.file_path_button.pack(side="right")

        # 下载按钮
        button_frame = tk.Frame(file_frame)
        button_frame.pack(pady=(0,5), fill="x")
        self.download_button = tk.Button(button_frame, text="下载附件", command=self.download_attachments, bg="#2196F3", fg="white", font=("微软雅黑", 10, "bold"))
        self.download_button.pack(side="left", expand=True, fill="x")

        # 附件信息展示框
        file_list_frame = tk.Frame(file_frame)
        file_list_frame.pack(fill="both", expand=True, pady=5)

        # 创建滚动条
        scrollbar = tk.Scrollbar(file_list_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        # 创建文本框用于输出信息
        self.file_info_text = tk.Text(file_list_frame, height=20, yscrollcommand=scrollbar.set)
        self.file_info_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.config(command=self.file_info_text.yview)
        
    def center_window(self):
        self.root.update_idletasks()
        screen_width = self.root.winfo_screenwidth()
        screen_height = self.root.winfo_screenheight()
        window_width = self.root.winfo_width()
        window_height = self.root.winfo_height()
        x = (screen_width - window_width) // 2
        y = (screen_height - window_height) // 2
        self.root.geometry(f"{window_width}x{window_height}+{x}+{y}")
    
    def toggle_imap_password_visibility(self):
        """切换IMAP密码可见性"""
        if self.imap_password_visible:
            # 当前是可见的，切换为隐藏
            self.password_entry.config(show="*")
            self.toggle_imap_password_button.config(text="👁")
            self.imap_password_visible = False
        else:
            # 当前是隐藏的，切换为可见
            self.password_entry.config(show="")
            self.toggle_imap_password_button.config(text="🔒")
            self.imap_password_visible = True

    def delete_account(self):
        """删除当前选中的账户"""
        if not self.current_account:
            messagebox.showwarning("警告", "请先选择一个账户")
            return
            
        result = messagebox.askyesno("确认删除", f"确定要删除账户 '{self.current_account}' 吗？")
        if result:
            del self.accounts[self.current_account]
            
            # 更新下拉框
            account_names = list(self.accounts.keys())
            self.email_combobox['values'] = account_names
            
            if account_names:
                self.email_combobox.set(account_names[0])
                self.current_account = account_names[0]
                self.update_fields_with_account(self.accounts[self.current_account])
            else:
                self.email_combobox.set('')
                self.current_account = None
                self.clear_account_fields()

            # 保存更新后的账户信息到配置文件
            self.save_settings() 
    
    def on_account_selected(self, event=None):
        """当用户从下拉框选择账户时调用"""
        selected_account = self.email_combobox.get()
        if selected_account in self.accounts:
            self.current_account = selected_account
            self.update_fields_with_account(self.accounts[selected_account])

    def update_fields_with_account(self, account_info):
        """使用指定账户信息更新界面字段"""
        self.imap_server_entry.delete(0, tk.END)
        self.imap_server_entry.insert(0, account_info.get("imap_server", ""))
        
        self.imap_port_entry.delete(0, tk.END)
        self.imap_port_entry.insert(0, account_info.get("imap_port", ""))
        
        self.password_entry.delete(0, tk.END)
        self.password_entry.insert(0, account_info.get("password", ""))
        
        self.file_path_entry.delete(0, tk.END)
        self.file_path_entry.insert(0, account_info.get("save_path", ""))
        
        # 重置密码可见性状态
        self.imap_password_visible = False
        self.password_entry.config(show="*")
        self.toggle_imap_password_button.config(text="👁")

    def clear_account_fields(self):
        """清空所有账户相关字段"""
        self.imap_server_entry.delete(0, tk.END)
        self.imap_port_entry.delete(0, tk.END)
        self.password_entry.delete(0, tk.END)
        self.file_path_entry.delete(0, tk.END)
        
        # 重置默认值
        self.imap_server_entry.insert(0, "imap.example.com")
        self.imap_port_entry.insert(0, "993")  # 修改为正确的IMAP SSL端口
        
        # 重置密码可见性状态
        self.imap_password_visible = False
        self.password_entry.config(show="*")
        self.toggle_imap_password_button.config(text="👁")
        
    def save_settings(self):
        """保存内容到配置文件"""
        current_email = self.email_combobox.get()

        if current_email:
            # 更新当前账户信息
            self.accounts[current_email] = {
                "email": current_email,
                "imap_server": self.imap_server_entry.get(),
                "imap_port": self.imap_port_entry.get(),
                "password": self.password_entry.get(),
                "save_path": self.file_path_entry.get()
            }
            self.current_account = current_email
        
        # 保存账户信息和上次使用的账户
        settings_to_save = {
            "accounts": self.accounts,
            "last_account": self.current_account
        }
        
        try:
            # 加密并保存配置
            encrypted_data = self._encrypt_config(settings_to_save)
            with open("config.json", "wb") as f:
                f.write(encrypted_data)
                
            # 更新下拉框选项
            account_names = list(self.accounts.keys())
            self.email_combobox['values'] = account_names
            
            # 设置当前选中项
            if current_email:
                self.email_combobox.set(current_email)
                
            messagebox.showinfo("成功", "保存成功")

        except Exception as e:
            print(f"保存设置时出错: {e}")
            messagebox.showerror("失败", f"保存失败: {e}")
    
    def load_settings(self):
        """加载已保存的设置"""
        try:
            # 读取并解密配置
            with open("config.json", "rb") as f:
                encrypted_data = f.read()
            
            settings = self._decrypt_config(encrypted_data)
            
            self.accounts = settings["accounts"]
            last_account = settings.get("last_account")
            
            # 更新下拉框选项
            account_names = list(self.accounts.keys())
            self.email_combobox['values'] = account_names
            
            # 如果有账户，优先使用上次选中的账户，否则选择第一个
            if account_names:
                if last_account and last_account in self.accounts:
                    # 使用上次选中的账户
                    self.email_combobox.set(last_account)
                    self.current_account = last_account
                    self.update_fields_with_account(self.accounts[last_account])
                else:
                    # 使用第一个账户
                    self.email_combobox.set(account_names[0])
                    self.current_account = account_names[0]
                    self.update_fields_with_account(self.accounts[account_names[0]])
            else:
                # 没有账户则使用默认值
                self.clear_account_fields()
                
        except FileNotFoundError:
            # 如果配置文件不存在，则使用默认值
            self.clear_account_fields()
        except Exception as e:
            # 如果解密失败，可能是因为MAC地址不同或其他问题
            messagebox.showerror("加载配置失败", f"加载设置时出错: {e}\n可能是由于更换了设备或网络适配器")
            self.clear_account_fields()

    def browse_folder(self):
        directory = filedialog.askdirectory()
        if directory:
            self.file_path_entry.delete(0, tk.END)
            self.file_path_entry.insert(0, directory)
            if self.current_account:
                self.accounts[self.current_account]["save_path"] = directory

    def download_attachments(self):
        """下载未读邮件的附件"""
        # 禁用下载按钮防止重复点击
        self.download_button.config(state=tk.DISABLED, text="下载中...")
        self.file_info_text.delete(1.0, tk.END)
        
        # 在线程中执行下载任务
        download_thread = threading.Thread(target=self._download_attachments_thread)
        download_thread.daemon = True
        download_thread.start()
        
    def _ui_update(self, func, *args, **kwargs):
        """安全地在主线程中更新UI"""
        self.root.after(0, lambda: func(*args, **kwargs))
        
    def _insert_text(self, text):
        """插入文本到信息框并滚动到最后"""
        self.file_info_text.insert(tk.END, text)
        self.file_info_text.see(tk.END)
        
    def _download_attachments_thread(self):
        """在后台线程中下载附件"""
        try:
            # 获取配置信息
            if not self.current_account:
                self._ui_update(lambda: messagebox.showerror("错误", "请先选择一个邮箱账户"))
                self._ui_update(self._reset_download_button)
                return

            self._ui_update(self._insert_text, "开始连接到邮箱服务器...\n")
            account_info = self.accounts[self.current_account]
            imap_server = account_info["imap_server"]
            imap_port = int(account_info["imap_port"])
            receiver_email = account_info["email"]  # 使用账户中保存的邮箱地址
            password = account_info["password"]
            save_path = account_info["save_path"]

            # 检查保存路径是否存在
            if not save_path or not os.path.exists(save_path):
                self._ui_update(lambda: messagebox.showerror("错误", "请选择有效的保存路径"))
                self._ui_update(self._reset_download_button)
                return
            
            if not all([imap_server, receiver_email, password]):
                self._ui_update(lambda: messagebox.showerror("错误", "请填写完整的邮箱配置信息"))
                self._ui_update(self._reset_download_button)
                return
                
            # 连接到IMAP服务器
            self._ui_update(self._insert_text, f"正在连接到 {imap_server}:{imap_port}...\n")
            mail = imaplib.IMAP4_SSL(imap_server, imap_port)
            mail.login(receiver_email, password)
            self._ui_update(self._insert_text, "登录成功\n")
            
            # 选择收件箱
            mail.select("inbox")
            
            # 搜索未读邮件
            status, messages = mail.search(None, 'UNSEEN')
            if status != 'OK':
                self._ui_update(self._insert_text, "搜索未读邮件失败\n")
                mail.logout()
                self._ui_update(self._reset_download_button)
                return
                
            email_ids = messages[0].split()
            self._ui_update(self._insert_text, f"找到 {len(email_ids)} 封未读邮件\n")
            
            if not email_ids:
                self._ui_update(self._insert_text, "没有未读邮件\n")
                mail.logout()
                self._ui_update(self._reset_download_button)
                return
            
            downloaded_count = 0
            
            # 遍历每封未读邮件
            for i, email_id in enumerate(email_ids):
                # 获取邮件数据
                status, msg_data = mail.fetch(email_id, '(RFC822)')
                if status != 'OK':
                    self._ui_update(self._insert_text, f"获取第 {i+1} 封邮件失败\n")
                    continue
                
                # 解析邮件
                msg = email.message_from_bytes(msg_data[0][1])
                subject = self._decode_str(msg["Subject"])
                self._ui_update(self._insert_text, f"处理邮件: {subject}\n")
                
                # 遍历邮件的每个部分
                for part in msg.walk():
                    if part.get_content_maintype() == 'multipart':
                        continue
                    if part.get_content_subtype() in ('plain', 'html'):
                        continue
                        
                    # 获取附件文件名
                    filename = part.get_filename()
                    if filename:
                        # 解码文件名
                        filename = self._decode_str(filename)
                        self._ui_update(self._insert_text, f"发现附件: {filename}\n")
                        
                        # 保存附件
                        filepath = os.path.join(save_path, filename)
                        with open(filepath, 'wb') as f:
                            f.write(part.get_payload(decode=True))
                            
                        self._ui_update(self._insert_text, f"已保存: {filename}\n")
                        downloaded_count += 1

            # 标记邮件为已读
            for email_id in email_ids:
                mail.store(email_id, '+FLAGS', '\\Seen')
                        
            mail.logout()
            self._ui_update(self._insert_text, f"完成! 共下载{downloaded_count}个附件\n已保存至{save_path}\n")
            # 保存配置
            self._ui_update(self.save_settings)

        except Exception as e:
            error_msg = f"下载过程中出现错误: {str(e)}"
            self._ui_update(self._insert_text, error_msg + "\n")
            print(f"Error: {e}")
        finally:
            self._ui_update(self._reset_download_button)
            
    def _decode_str(self, s):
        """解码邮件中的字符串"""
        if not s:
            return ""
        try:
            decoded_fragments = decode_header(s)
            decoded_str = ""
            for fragment, encoding in decoded_fragments:
                if isinstance(fragment, bytes):
                    if encoding:
                        decoded_str += fragment.decode(encoding)
                    else:
                        decoded_str += fragment.decode()
                else:
                    decoded_str += fragment
            return decoded_str
        except Exception as e:
            print(f"解码字符串时出错: {e}")
            return str(s)
            
    def _reset_download_button(self):
        """重置下载按钮状态"""
        self.download_button.config(state=tk.NORMAL, text="下载")

    def _get_cipher(self):
        # 获取MAC地址
        mac = uuid.getnode()
        mac_str = str(mac).encode()
        app_identifier = "ReceiveFromEmail_App_v1".encode()
        key_material = hashlib.sha256(mac_str + app_identifier).digest()
        key = base64.urlsafe_b64encode(key_material)
        return Fernet(key)
    
    def _encrypt_config(self, data):
        """加密配置数据"""
        cipher = self._get_cipher()
        json_data = json.dumps(data, ensure_ascii=False, indent=4)
        encrypted_data = cipher.encrypt(json_data.encode('utf-8'))
        return encrypted_data
    
    def _decrypt_config(self, encrypted_data):
        """解密配置数据"""
        cipher = self._get_cipher()
        decrypted_data = cipher.decrypt(encrypted_data)
        return json.loads(decrypted_data.decode('utf-8'))

if __name__ == "__main__":
    app = ReceiveFromEmail()
    app.root.mainloop()